import { dom, EventHandler, Nodes } from '@knno/dom';
import { paginatorStyle } from './paginator.css';
import SVGPrev from '@material-design-icons/svg/filled/keyboard_arrow_left.svg';
import SVGNext from '@material-design-icons/svg/filled/keyboard_arrow_right.svg';
import SVGMore from '@material-design-icons/svg/filled/more_horiz.svg';
import { isDescendant } from '../../tools/utils';
import { DATA } from '../symbol';

interface ActivePageEventDetail {
	page: number;
}

type ActivePageEvent = CustomEvent<ActivePageEventDetail>;

export interface PaginatorEventMap {
	activepage: ActivePageEvent;
}
export type PaginatorEventKey = keyof PaginatorEventMap;
export type PaginatorEventHandler<T extends PaginatorEventKey, O extends Nodes> = (
	this: O,
	event: PaginatorEventMap[T]
) => void;

export interface Paginator {
	on<K extends keyof PaginatorEventMap>(
		event: K,
		listener: PaginatorEventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
	on<K extends keyof HTMLElementEventMap>(
		event: K,
		listener: EventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
	off<K extends keyof PaginatorEventMap>(
		event: K,
		listener: PaginatorEventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
	off<K extends keyof HTMLElementEventMap>(
		event: K,
		listener: EventHandler<K, this>,
		options?: boolean | AddEventListenerOptions
	): this;
}

export class Paginator extends Nodes {
	private [DATA] = {
		act: 0,
		pages: 0,
		buttons: 9,
	};

	constructor() {
		const root = dom.div(paginatorStyle);
		root.on('click', (event) => {
			const elem = this.children()
				.elems()
				.filter((elem) => isDescendant([elem], event.target as HTMLElement))[0];
			if (elem) {
				const el = dom.wrap(elem);
				if (!el.class().includes('disable')) {
					const v = el.prop('page');
					if (typeof v === 'number') {
						const srcCount = this.children().elems().length;
						let idx = this.children().elems().indexOf(elem);
						this.active(v);
						this.emit(new CustomEvent('activepage', { detail: { page: v } }));
						const elems = this.children().elems();
						if (elems.length > srcCount && idx > srcCount / 2) {
							idx++;
						}
						(elems[Math.min(idx, elems.length - 1)] as HTMLElement).focus();
					}
				}
			}
		});
		super(root);
	}

	private render1() {
		this.html('');
		this.append(
			dom
				.button('svg prev', this[DATA].act == 1 ? 'disable' : '')
				.html(SVGPrev)
				.prop('page', this[DATA].act - 1),
			dom.button('active').text(this[DATA].act + ''),
			dom
				.button('svg next', this[DATA].act == this[DATA].pages ? 'disable' : '')
				.html(SVGNext)
				.prop('page', this[DATA].act + 1)
		);
	}

	private render2() {
		this.html('');
		this.append(
			dom
				.button('svg prev', this[DATA].act == 1 ? 'disable' : '')
				.html(SVGPrev)
				.prop('page', this[DATA].act - 1),
			dom.button('active').text(this[DATA].act + ''),
			dom.text('/'),
			dom.button().text(this[DATA].pages + ''),
			dom
				.button('svg next', this[DATA].act == this[DATA].pages ? 'disable' : '')
				.html(SVGNext)
				.prop('page', this[DATA].act + 1)
		);
	}

	private render() {
		if (this[DATA].pages < 1) {
			this[DATA].pages = 1;
		}
		if (this[DATA].act < 1) {
			this[DATA].act = 1;
		}
		if (this[DATA].act > this[DATA].pages) {
			this[DATA].act = this[DATA].pages;
		}
		if (this[DATA].buttons < 1) {
			this[DATA].buttons = 1;
		}
		if (this[DATA].buttons == 2) {
			this.render2();
			return;
		} else if (this[DATA].buttons == 1) {
			this.render1();
			return;
		}
		let buttons = this[DATA].buttons - 2;
		let diff = 0;
		if (this[DATA].buttons % 2 === 0) {
			diff = 1;
			buttons -= 1;
		}
		const helf = (buttons - 1) / 2;
		const arr: Nodes[] = [];
		let begin = Math.max(2, this[DATA].act - helf);
		const end = Math.min(begin + helf * 2 + diff, this[DATA].pages - 1);
		begin = Math.max(2, Math.min(end - (helf * 2 + diff), begin));
		arr.push(
			dom
				.button(this[DATA].act === 1 ? 'active' : '')
				.text(1 + '')
				.prop('page', 1)
		);
		if (begin >= 3) {
			arr.push(
				dom
					.button('svg more')
					.html(SVGMore)
					.prop('page', begin - 1)
			);
		}
		for (let i = begin; i <= end; i++) {
			arr.push(
				dom
					.button(i === this[DATA].act ? 'active' : '')
					.text(i + '')
					.prop('page', i)
			);
		}
		if (end <= this[DATA].pages - 2) {
			arr.push(
				dom
					.button('svg more')
					.html(SVGMore)
					.prop('page', end + 1)
			);
		}
		if (this[DATA].pages > 1) {
			arr.push(
				dom
					.button(this[DATA].act === this[DATA].pages ? 'active' : '')
					.text(this[DATA].pages + '')
					.prop('page', this[DATA].pages)
			);
		}

		this.html('');
		this.append(
			dom
				.button('svg prev', this[DATA].act == 1 ? 'disable' : '')
				.html(SVGPrev)
				.prop('page', this[DATA].act - 1),
			...arr,
			dom
				.button('svg next', this[DATA].act == this[DATA].pages ? 'disable' : '')
				.html(SVGNext)
				.prop('page', this[DATA].act + 1)
		);
	}

	active(): number;
	active(value: number): this;
	active(value?: number): number | this {
		if (value === undefined) {
			return this[DATA].act;
		}
		this[DATA].act = value;
		this.render();
		return this;
	}

	pages(): number;
	pages(value: number): this;
	pages(value?: number): number | this {
		if (value === undefined) {
			return this[DATA].pages;
		}
		this[DATA].pages = value;
		this.render();
		return this;
	}

	buttons(): number;
	buttons(value: number): this;
	buttons(value?: number): number | this {
		if (value === undefined) {
			return this[DATA].buttons;
		}
		this[DATA].buttons = value;
		this.render();
		return this;
	}
}

export function paginator(...className: string[]): Paginator {
	return new Paginator().addClass(...className);
}
